package com.ruoyi.system.core;

import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.system.api.domain.SmsResult;
import com.ruoyi.system.config.AliyunSmsProperties;
import com.ruoyi.system.support.AliyunSmsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 短信服务实现类
 * 
 * @author ruoyi
 */
@Service
public class DefaultSmsService implements SmsService {

    private static final Logger log = LoggerFactory.getLogger(DefaultSmsService.class);

    @Autowired
    private AliyunSmsProperties props;

    @Autowired
    private RedisService redis;

    // Redis Key前缀
    private static final String SMS_CODE_PREFIX = "sms:code:";
    private static final String SMS_LIMIT_PREFIX = "sms:limit:";

    @Override
    public SmsResult sendVerificationCode(String phoneNumber) {
        try {
            Integer len = props.getCodeLength();
            if (len == null || len <= 0) {
                log.error("短信验证码长度配置错误: {}", len);
                return SmsResult.fail(maskPhone(phoneNumber), "系统配置错误", null);
            }
            String code = generateCode(len);
            return sendVerificationCode(phoneNumber, code);
        } catch (Exception e) {
            log.error("发送验证码异常: phoneNumber={}, error={}", maskPhone(phoneNumber), e.getMessage(), e);
            return SmsResult.fail(maskPhone(phoneNumber), "系统异常，请稍后重试", null);
        }
    }

    @Override
    public SmsResult sendVerificationCode(String phoneNumber, String code) {
        try {
            // 参数校验
            if (!StringUtils.hasText(phoneNumber) || !StringUtils.hasText(code)) {
                return SmsResult.fail(maskPhone(phoneNumber), "手机号或验证码为空", null);
            }

            // 检查发送频率限制
            String limitKey = SMS_LIMIT_PREFIX + phoneNumber;
            if (Boolean.TRUE.equals(redis.hasKey(limitKey))) {
                return SmsResult.fail(maskPhone(phoneNumber), "发送过于频繁，请稍后再试", null);
            }

            // 检查过期时间配置
            Integer expire = props.getExpireMinutes();
            if (expire == null || expire <= 0) {
                log.error("短信验证码过期时间配置错误: {}", expire);
                return SmsResult.fail(maskPhone(phoneNumber), "系统配置错误", null);
            }

            // 构建短信参数 - 使用标准JSON格式
            String paramJson = String.format("{\"code\":\"%s\",\"minute\":\"%d\"}", code, expire);

            // 调用阿里云短信API
            String response = AliyunSmsUtil.sendSms(
                    props.getHost(), props.getPath(), props.getMethod(), props.getAppcode(),
                    phoneNumber, props.getSmsSignId(), props.getTemplateId(), paramJson);

            log.info("短信发送响应: phoneNumber={}, response={}", maskPhone(phoneNumber), response);

            // 判断发送是否成功
            if (response != null && (response.contains("\"msg\":\"ok\"") || response.contains("\"code\":\"0\""))) {
                // 存储验证码和限流标记
                redis.setCacheObject(SMS_CODE_PREFIX + phoneNumber, code, expire.longValue(), TimeUnit.MINUTES);
                redis.setCacheObject(limitKey, "1", 120L, TimeUnit.SECONDS);

                log.info("验证码发送成功: phoneNumber={}", maskPhone(phoneNumber));
                return SmsResult.ok(maskPhone(phoneNumber), "验证码发送成功", code);
            } else {
                log.warn("验证码发送失败: phoneNumber={}, response={}", maskPhone(phoneNumber), response);
                return SmsResult.fail(maskPhone(phoneNumber), "验证码发送失败", response);
            }
        } catch (Exception e) {
            log.error("发送指定验证码异常: phoneNumber={}, code={}, error={}", maskPhone(phoneNumber), code, e.getMessage(), e);
            return SmsResult.fail(maskPhone(phoneNumber), "系统异常，请稍后重试", null);
        }
    }

    @Override
    public boolean verifyCode(String phoneNumber, String inputCode) {
        try {
            if (!StringUtils.hasText(phoneNumber) || !StringUtils.hasText(inputCode)) {
                log.warn("验证码校验参数为空: phoneNumber={}, inputCode={}", maskPhone(phoneNumber), inputCode);
                return false;
            }

            Object cachedObj = redis.getCacheObject(SMS_CODE_PREFIX + phoneNumber);
            String cached = cachedObj == null ? null : String.valueOf(cachedObj);
            String input = String.valueOf(inputCode);

            // 兼容历史上将验证码以整数形式写入 Redis 的情况：
            // 去除前导零后再比较，避免 "037019" 与 37019 不相等的问题
            String normalizedCached = (cached == null) ? null : cached.replaceFirst("^0+(?!$)", "");
            String normalizedInput = input.replaceFirst("^0+(?!$)", "");

            boolean isValid = StringUtils.hasText(normalizedCached) && normalizedCached.equals(normalizedInput);

            log.info("验证码校验结果: phoneNumber={}, isValid={}", maskPhone(phoneNumber), isValid);
            return isValid;
        } catch (Exception e) {
            log.error("验证码校验异常: phoneNumber={}, inputCode={}, error={}", maskPhone(phoneNumber), inputCode, e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean deleteCode(String phoneNumber) {
        try {
            if (!StringUtils.hasText(phoneNumber)) {
                log.warn("删除验证码参数为空: phoneNumber={}", maskPhone(phoneNumber));
                return false;
            }

            boolean result = redis.deleteObject(SMS_CODE_PREFIX + phoneNumber);
            log.info("删除验证码结果: phoneNumber={}, result={}", maskPhone(phoneNumber), result);
            return result;
        } catch (Exception e) {
            log.error("删除验证码异常: phoneNumber={}, error={}", maskPhone(phoneNumber), e.getMessage(), e);
            return false;
        }
    }

    /**
     * 生成随机验证码
     */
    private String generateCode(Integer length) {
        if (length == null || length <= 0) {
            length = 6; // 默认6位
        }

        ThreadLocalRandom random = ThreadLocalRandom.current();
        StringBuilder code = new StringBuilder();

        for (int i = 0; i < length; i++) {
            code.append(random.nextInt(10));
        }

        return code.toString();
    }

    /**
     * 手机号脱敏处理
     */
    private String maskPhone(String phone) {
        if (!StringUtils.hasText(phone) || phone.length() < 4) {
            return "****";
        }
        return "****" + phone.substring(phone.length() - 4);
    }
}